package peace.gui.controls.list
{
import flash.display.DisplayObject;
import flash.display.Shape;
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFormat;

import peace.gui.controls.Control;
import peace.gui.controls.GroupSelection;
import peace.gui.controls.SelectEvent;
import peace.gui.controls.buttons.PushButton;
import peace.gui.controls.scroll.Scrollpane;
import peace.gui.layout.Align;
import peace.gui.layout.ColumnLayout;
import peace.gui.layout.Container;
	
/**
 * Лист, параметризуеымй группой объектов (Object)
 * 
 * @example
 * <listing>
		var l:ListBox = new ListBox(null, true);
		l.data = ["первый","второй","третий","четвертый","пятый","шестой"];
		l.selectedIndexes = [1,3]
		addChild(l);
		l.x = l.y = 50;
		l.addEventListener(SelectEvent.CHANGE, function(e:SelectEvent):void
		{
			Logger.msg(e.selection);
		});
	</listing>
*/	
public class ListBox extends Control
{
	/**
	 * 
	 */
	protected static const DEFAULT_WIDTH:uint = 100;
	/**
	 * массив объектов данных
	 */	
	protected var _data:Array;
	/**
	 * 
	 */	
	protected var group:GroupSelection;
	/**
	 * 
	 */	
	protected var container:Container = new Container(new ColumnLayout());
	/**
	 * 
	 */
	protected var sp:Scrollpane;
	
	protected var textFieldClass:Class;
	protected var pushButtonClass:Class;

	/**
	 * 
	 * @param data массив объектов данных. В качестве метки берем toString()
	 * @param allowMultipleSelection
	 * @param labelClass
	 * @param pushButtonClass
	 * @param scrollPaneClass
	 * 
	 */
	public function ListBox (	data:Array = null,
								allowMultipleSelection:Boolean=false,
								textFieldClass:Class = null,
								pushButtonClass:Class = null, 
								scrollPaneClass:Class = null)
	{
		this.textFieldClass = textFieldClass;
		this.pushButtonClass = pushButtonClass;
		
		group = new GroupSelection(null, allowMultipleSelection);
		// делегируем событие дальше
		group.addEventListener(SelectEvent.CHANGE, onChangeSelection);
		
		sp = scrollPaneClass 	? new scrollPaneClass(DEFAULT_WIDTH,container.height,false) 
								: new Scrollpane(DEFAULT_WIDTH,container.height,false)
		addChild(sp);
		sp.content = container;
		
		width = DEFAULT_WIDTH;
		
		this.data = data;
	}
	/**
	 * Обновляем список селекторов с новыми данными
	 * 
	 */	
	public function set data (array:Array):void
	{
		if (!array) return;
		
		_data = array;
		
		container.removeAll();
		group.removeAll();
		
		var i:int;
		var s:PushButton;
		for(i = 0; i < _data.length; i++)
		{
			s = createSelector(textFieldClass, pushButtonClass, _data[i].toString());
			group.add(s);
			container.add (s);
		}
		container.arrange();
		
		// чтобы не оставалось пустого места при уменьшении высоты контейнера
		if (sp.height == 0 || container.height < sp.height)
		{
			height = container.height;
		} 
	}
	/**
	 * 
	 * @return 
	 * 
	 */	
	public function get data ():Array
	{
		return _data;
	}
	/**
	 * 
	 * @param lc Class
	 * @param bc Class
	 * @param label String
	 * 
	 */	
	protected function createSelector(lc:Class, bc:Class, label:String):PushButton
	{
		var b:PushButton;
		var skin:ItemSkin = new ItemSkin();
		if (bc)
		{
			b = new bc();
		}
		else
		{
			b = new PushButton(skin.out,skin.over,skin.down,skin.hit,skin.selected); 
		}
		
		var l:TextField = lc ? new lc() : skin.label;
		b.setIcon(l, Align.LEFT);
		l.text = label;

		if (!bc)
		{
			b.height = l.height + 4;
		}
		
		b.width = sp.width - sp.verticalBarWidth;
		
		return b;
	}
	/**
	 * Задаем выделенное значение 
	 * 
	 * @param v объект или массив объектов
	 * 
	 */
	override public function set value (v:*):void
	{
		if (!v)
		{
			group.selection = null;
			return;
		}
		
		var controls:Array = [];
		var items:Array = group.controls;
		var arr:Array = v is Array ? v : [v];
		var index:int;
		var i:int;
		for (i = 0; i < arr.length; i++)
		{
			index = _data.indexOf(arr[i]);
			if (index == -1) continue;
			controls.push (items[index]);
		}
		group.selection = controls;
	}
	/**
	 * 
	 * @return объект или массив объектов
	 * 
	 */
	override public function get value ():*
	{
		var indexes:Array = this.selectedIndexes;
		if (indexes.length == 1)
		{
			return _data[indexes[0]]
		}
		else if (indexes.length > 1)
		{
			var result:Array = [];
			var i:int;
			for (i = 0; i < indexes.length; i++)
			{
				result.push (_data[indexes[i]]);	
			}
			return result;
		}
		return null;
	}
	/**
	 * Выделяем по индексу элемента
	 *  
	 * @param index
	 * 
	 */	
	public function set selectedIndex (index:int):void
	{
		this.value = _data[index];
	}
	/**
	 * 
	 * @return 
	 * 
	 */	
	public function get selectedIndex ():int
	{
		var indexes:Array = this.selectedIndexes;
		return indexes.length > 0 ? indexes[0] : -1;
	}
	/**
	 * Присваиваем значение в виде массива индексов
	 * 
	 * @param indexes
	 * 
	 */	
	public function set selectedIndexes (indexes:Array):void
	{
		var items:Array = group.controls;
		var controls:Array = [];
		var i:int;
		for each (i in indexes)
		{
			controls.push (items[i]); 
		}
		group.selection = controls;
	}
	/**
	 *  
	 * @return значение контрола в форме индексов 
	 * 
	 */	
	public function get selectedIndexes ():Array
	{
		var s:* = group.selection;
		if (!s) return [];
		
		var items:Array = group.controls;
		var selection:Array = s is Array ? s : [s];
		var result:Array = [];
		var b:PushButton;
		for each (b in selection)
		{
			result.push (items.indexOf(b));
		}
		return result;
	}
	/**
	 * 
	 * @param e
	 * 
	 */	
	protected function onChangeSelection (e:SelectEvent):void
	{
		dispatchEvent(new SelectEvent(SelectEvent.CHANGE, this.value));
	}
	/**
	 * Возможность установить элементам листа поведение радиогруппы
	 * 
	 * @param b Boolean
	 * 
	 */	
	public function set allowRadioMode (b:Boolean):void
	{
		group.allowRadioMode = b;
	}
	/**
	 * 
	 * @return 
	 * 
	 */	
	override public function get width():Number
	{
		return sp.width;
	}
	/**
	 * 
	 * @param n
	 * 
	 */
	override public function set width(n:Number):void
	{
		sp.width = n;
		
		var b:Sprite;
		for each (b in container.children)
		{
			b.width = n-sp.verticalBarWidth;
		}
		container.arrange();
	}
	/**
	 * 
	 * @return 
	 * 
	 */	
	override public function get height():Number
	{
		return sp.height;
	}
	/**
	 * 
	 * @param n
	 * 
	 */
	override public function set height(n:Number):void
	{
		sp.height = n;
	}
	
}
}

import flash.display.DisplayObject;
import flash.text.TextField;
import flash.display.Sprite;
import flash.display.Shape;
import flash.text.TextFormat;
import flash.text.TextFieldAutoSize;
	

internal class ItemSkin
{
	public var out:DisplayObject = null; 	
	public var over:DisplayObject = null;
	public var down:DisplayObject = null;
	public var hit:Sprite = null;
	public var selected:DisplayObject = null;
	public var label:TextField = null;
	
	public function ItemSkin (	out:DisplayObject = null, 	
								over:DisplayObject = null, 
								down:DisplayObject = null, 
								hit:Sprite = null,
								selected:DisplayObject = null,
								labelClass:Class = null)
	{
		this.out = out==null ? getOut() : out;
		this.over = over==null ? getOver() : over;
		this.down = down==null ? getDown() : down;
		this.hit = hit==null ? getHit() : hit;
		this.selected = selected==null ? getSelect() : selected;
		this.label = getLabel(labelClass);
	}
	
	private function getOut():DisplayObject
	{
		if (out!=null)
			return out;
		else
		{
			var s:Shape = new Shape();
			s.graphics.lineStyle(0,0,0);
			s.graphics.beginFill(0xffffff);
			s.graphics.drawRect(0,0,10,10);
			return s;
		}	
	}
	private function getOver():DisplayObject
	{
		if (over!=null)
			return over;
		else
		{
			var s:Shape = new Shape();
			s.graphics.lineStyle(0,0,0);
			s.graphics.beginFill(0xB0D8FF);
			s.graphics.drawRect(0,0,10,10);
			return s;
		}	
	}
	private function getDown():DisplayObject
	{
		if (down!=null)
			return down;
		else
		{
			var s:Shape = new Shape();
			s.graphics.lineStyle(0,0,0);
			s.graphics.beginFill(0x4AA5FF);
			s.graphics.drawRect(0,0,10,10);
			return s;
		}	
	}
	private function getHit():Sprite
	{
		if (hit!=null)
			return hit;
		else
		{
			return null;
		}	
	}
	private function getSelect():DisplayObject
	{
		if (selected!=null)
			return selected;
		else
		{
			return getDown();
		}	
	}
	private function getLabel(labelClass:Class):TextField
	{
		var t:TextField = labelClass ? new labelClass() : new TextField();
		if (!labelClass)
		{
			t.defaultTextFormat =  new TextFormat("arial", 12);
			t.selectable = false;
			t.autoSize = TextFieldAutoSize.LEFT;
		}
		return t;
	}
}